/**
 * 弹性控制工具函数
 * 用于处理函数执行失败的情况，提供重试、超时控制和错误处理，提高系统稳定性和可靠性
 */

import { timerManager } from '../common/timer-manager';

/**
 * 自动重试失败的函数
 * @template T - 函数返回类型
 * @param {() => Promise<T>} func - 要重试的异步函数
 * @param {object} [options] - 配置选项
 * @param {number} [options.maxRetries=3] - 最大重试次数
 * @param {number} [options.delay=1000] - 重试间隔(毫秒)
 * @param {(error: Error, attempt: number) => boolean} [options.shouldRetry] - 判断是否应该重试的函数
 * @returns {Promise<T>} 函数执行结果的Promise
 * @example
 * const fetchData = () => fetch('https://api.example.com/data');
 * const data = await retry(fetchData, {
 *   maxRetries: 5,
 *   delay: 2000,
 *   shouldRetry: (error) => error.status === 500
 * });
 */
export async function retry<T>(
  func: () => Promise<T>,
  options: {
    maxRetries?: number;
    delay?: number;
    shouldRetry?: (error: Error, attempt: number) => boolean;
  } = {}
): Promise<T> {
  const {
    maxRetries = 3,
    delay = 1000,
    shouldRetry = () => true
  } = options;

  let lastError: Error;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await func();
    } catch (error) {
      lastError = error as Error;

      // 如果是最后一次尝试，或者不应该重试，则抛出错误
      if (attempt === maxRetries || !shouldRetry(lastError, attempt + 1)) {
        throw lastError;
      }

      // 等待指定的延迟时间
      await new Promise(resolve => {
        const timeoutId = timerManager.addTimer(delay, () => resolve(undefined));
        // 确保清除定时器
        return () => timerManager.removeTimer(timeoutId);
      });
    }
  }

  // 这里实际上不会执行到，因为最后一次失败会在循环中抛出错误
  throw lastError!;
}

/**
 * 指数退避重试策略
 * @template T - 函数返回类型
 * @param {() => Promise<T>} func - 要重试的异步函数
 * @param {object} [options] - 配置选项
 * @param {number} [options.maxRetries=5] - 最大重试次数
 * @param {number} [options.initialDelay=1000] - 初始延迟时间(毫秒)
 * @param {number} [options.backoffFactor=2] - 退避因子
 * @param {number} [options.maxDelay=30000] - 最大延迟时间(毫秒)
 * @param {(error: Error, attempt: number) => boolean} [options.shouldRetry] - 判断是否应该重试的函数
 * @returns {Promise<T>} 函数执行结果的Promise
 * @example
 * const fetchData = () => fetch('https://api.example.com/data');
 * const data = await exponentialBackoff(fetchData, {
 *   maxRetries: 8,
 *   initialDelay: 500,
 *   backoffFactor: 1.5
 * });
 */
export async function exponentialBackoff<T>(
  func: () => Promise<T>,
  options: {
    maxRetries?: number;
    initialDelay?: number;
    backoffFactor?: number;
    maxDelay?: number;
    shouldRetry?: (error: Error, attempt: number) => boolean;
  } = {}
): Promise<T> {
  const {
    maxRetries = 5,
    initialDelay = 1000,
    backoffFactor = 2,
    maxDelay = 30000,
    shouldRetry = () => true
  } = options;

  let lastError: Error;

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await func();
    } catch (error) {
      lastError = error as Error;

      // 如果是最后一次尝试，或者不应该重试，则抛出错误
      if (attempt === maxRetries || !shouldRetry(lastError, attempt + 1)) {
        throw lastError;
      }

      // 计算指数退避延迟时间
      const calculatedDelay = Math.min(
        initialDelay * Math.pow(backoffFactor, attempt),
        maxDelay
      );

      // 等待计算的延迟时间
      await new Promise(resolve => {
        const timeoutId = timerManager.addTimer(calculatedDelay, () => resolve(undefined));
        // 确保清除定时器
        return () => timerManager.removeTimer(timeoutId);
      });
    }
  }

  // 这里实际上不会执行到，因为最后一次失败会在循环中抛出错误
  throw lastError!;
}

/**
 * 为函数执行设置超时时间
 * @template T - 函数返回类型
 * @param {() => Promise<T>} func - 要执行的异步函数
 * @param {number} ms - 超时时间(毫秒)
 * @param {Error} [timeoutError] - 超时时抛出的错误
 * @returns {Promise<T>} 函数执行结果的Promise
 * @example
 * const fetchWithTimeout = timeout(() => fetch('https://api.example.com/data'), 5000);
 * try {
 *   const response = await fetchWithTimeout;
 *   // 处理响应
 * } catch (error) {
 *   if (error.name === 'TimeoutError') {
 *     console.log('请求超时');
 *   }
 * }
 */
export function timeout<T>(
  func: () => Promise<T>,
  ms: number,
  timeoutError?: Error
): Promise<T> {
  return new Promise((resolve, reject) => {
    // 创建一个超时Promise
    const timeoutPromise = new Promise<never>((_, timeoutReject) => {
      const timeoutId = timerManager.addTimer(ms, () => {
        // 创建基本错误对象
        const error = timeoutError || new Error('Function execution timed out');
        // 手动添加cause属性（在支持的环境中）
        if (typeof error === 'object' && error !== null) {
          (error as any).cause = 'timeout';
        }
        timeoutReject(error);
      });

      // 确保清除定时器以防止内存泄漏
      timeoutPromise.finally(() => timerManager.removeTimer(timeoutId));
    });

    // 使用Promise.race来竞争执行函数和超时
    Promise.race([func(), timeoutPromise])
      .then(resolve)
      .catch(reject);
  });
}

/**
 * 为函数添加错误处理
 * @template T - 函数类型
 * @param {T} func - 要添加错误处理的函数
 * @param {(error: Error, ...args: Parameters<T>) => void} errorHandler - 错误处理函数
 * @returns {T & { original: T }} 包装后的函数，保留原始函数的引用
 * @example
 * const fetchWithErrorHandling = withErrorHandling(
 *   async (url) => {
 *     const response = await fetch(url);
 *     if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
 *     return response.json();
 *   },
 *   (error, url) => {
 *     console.error(`Failed to fetch ${url}:`, error);
 *     return { error: error.message };
 *   }
 * );
 * 
 * const data = await fetchWithErrorHandling('https://api.example.com/data');
 */
export function withErrorHandling<T extends (...args: any[]) => any>(
  func: T,
  errorHandler: (error: Error, ...args: Parameters<T>) => ReturnType<T>
): T & { original: T } {
  const wrappedFunction = function (...args: Parameters<T>): ReturnType<T> {
    try {
      return func(...args);
    } catch (error) {
      return errorHandler(error as Error, ...args);
    }
  } as T & { original: T };

  // 保留对原始函数的引用
  wrappedFunction.original = func;
  
  return wrappedFunction;
}

/**
 * 为Promise设置超时
 * @template T - Promise的解析类型
 * @param {Promise<T>} promise - 要设置超时的Promise
 * @param {number} ms - 超时时间(毫秒)
 * @param {Error} [timeoutError] - 超时时抛出的错误
 * @returns {Promise<T>} 包装后的Promise
  * @example
  * const promise = fetch('https://api.example.com/data');
  * try {
  *   const response = await promiseTimeout(promise, 5000);
  *   // 处理响应
  * } catch (error) {
  *   if (error.name === 'TimeoutError') {
  *     console.log('请求超时');
  *   }
  * }
 */
export function promiseTimeout<T>(
  promise: Promise<T>,
  ms: number,
  timeoutError?: Error
): Promise<T> {
  return new Promise((resolve, reject) => {
    // 创建一个超时Promise
    const timeoutPromise = new Promise<never>((_, timeoutReject) => {
      const timeoutId = timerManager.addTimer(ms, () => {
        // 创建基本错误对象
        const error = timeoutError || new Error('Promise timed out');
        // 手动添加cause属性（在支持的环境中）
        if (typeof error === 'object' && error !== null) {
          (error as any).cause = 'timeout';
        }
        timeoutReject(error);
      });

      // 确保清除定时器以防止内存泄漏
      timeoutPromise.finally(() => timerManager.removeTimer(timeoutId));
    });

    // 使用Promise.race来竞争原始Promise和超时
    Promise.race([promise, timeoutPromise])
      .then(resolve)
      .catch(reject);
  });
}